#include <iostream>
#include "Nota.h"

using namespace std;


Nota :: Nota(){
    this->letra = 'C';
    this->octava = 1;
    this->numero = 1;
    this->sostenido = false;
}
              
Nota :: Nota(char letra, int octava, char sostenido){
    this->letra = letra;
    this->octava = octava;
    this->numero = (octava - 1) * 12 + letraANumero(letra);
    //si se ingresa un E# o un B# los toma como E y B respectivamente
    if(sostenido == '#' && letra != 'E' && letra != 'B'){
        this->sostenido = true;
        this->numero++;
    }
    else this->sostenido = false;
}

Nota :: Nota(const Nota &n){
    this->letra = n.letra;
    this->octava = n.octava;
    this->numero = n.numero;
    this->sostenido = n.sostenido;
}

Nota :: ~Nota(){};

Nota & Nota :: operator = (const Nota &n){
    this->letra = n.letra;
    this->octava = n.octava;
    this->sostenido = n.sostenido;
    this->numero = n.numero;
    return *this;
}

Nota Nota :: operator + (const int num) const{
    
    Nota aux(*this);
    int numeronota;
              
    if( (aux.numero + num) < 97 )aux.numero += num;
    else aux.numero = 96;

    aux.octava = (aux.numero - 1) / 12 + 1;
    numeronota = aux.numero % 12;
     
    if(numeroALetra(numeronota) == '#'){
        aux.sostenido = true;
        numeronota--;
    }else aux.sostenido = false;
     
    aux.letra = numeroALetra(numeronota % 12);
     
          
    return aux;
     
}

Nota Nota :: operator - (const int num) const{
    
    Nota aux(*this);
    int numeronota;
     
    if( (aux.numero - num) > 1 )aux.numero -= num;
    else aux.numero = 1;

    aux.octava = (aux.numero - 1) / 12 + 1;
    numeronota = aux.numero % 12;
     
    if(numeroALetra(numeronota) == '#'){
        aux.sostenido = true;
        numeronota--;
    }else aux.sostenido = false;
     
    aux.letra = numeroALetra(numeronota % 12);
    return aux;
     
}

bool Nota :: operator == (const Nota &n) const{
    if(numero == n.numero) return true;
    else return false;
}

bool Nota :: operator < (const Nota &n) const{
    if(numero < n.numero) return true;
    return false;
}

bool Nota :: operator > (const Nota &n) const{
    if(numero > n.numero) return true;
    return false;
}

bool Nota :: operator <= (const Nota &n) const{
    if(numero <= n.numero) return true;
    return false;
}

bool Nota :: operator >= (const Nota &n) const{
    if(numero >= n.numero) return true;
    return false;
}

ostream & operator << (ostream &sal, const Nota &n){
    if(n.numero >= 1 && n.numero <= 96){
        sal << n.letra;
        sal << n.octava;
        if( n.sostenido ) sal << '#';
        sal << endl;
    }
    return sal;
}

istream & operator >> (istream &in, Nota &n){
    char notaEntrada[4];
    
    in >> notaEntrada;
    
    n.letra = notaEntrada[0];
    n.octava = notaEntrada[1] - 48; //Conversion de el numero ASCII a numero real. Ver tabla ASCII.
    n.numero = (n.octava - 1) * 12 + n.letraANumero(n.letra);
    
    if(notaEntrada[2] == '#' && n.letra != 'E' && n.letra != 'B'){
        n.sostenido = true;
        n.numero++;
    }
    else n.sostenido = false;
    
    return in;
}

Nota Nota::absoluta(){
    Nota aux(*this);
    if(sostenido == true)return aux - 1;
    else return aux;
}


Nota Nota::maximaAbsoluta(){
    Nota aux(*this);
    if(sostenido == true)return aux + 1;
    else return aux;
}

bool Nota::esB(){
    return ( this->letra == 'B' );
}

int Nota::letraANumero(const char letra) const{
    int num;
    switch(letra){
        case 'C': num = 1; break;
        case 'D': num = 3; break;
        case 'E': num = 5; break;
        case 'F': num = 6; break;
        case 'G': num = 8; break;
        case 'A': num = 10; break;
        case 'B': num = 12; break;
    }
    return num;
}

char Nota::numeroALetra(const int num) const{
    char letra;
    switch(num){
        case 1: letra = 'C'; break;
        case 3: letra = 'D'; break;
        case 5: letra = 'E'; break;
        case 6: letra = 'F'; break;
        case 8: letra = 'G'; break;
        case 10: letra = 'A'; break;
        case 12: letra = 'B'; break;
        case 0: letra = 'B'; break;         
        default: letra = '#'; break;
    }
    return letra;
}
